#include <bits/stdc++.h>
const int N = 100000 + 10;
using namespace std;
typedef long long ll;
vector<int> adj[N];
int n, m, r, p, cnt;
int son[N], depth[N], fa[N], siz[N];
int id[N], top[N], w[N];
ll c1[N], c2[N];
inline int lowbit(int x) { return x & -x; }
inline void add(int l, int r, int x) {
  x %= p;
  int ad1 = (ll)(l - 1) * x % p;
  int ad2 = (ll)r * x % p;
  for (int t = l; t <= n; t += lowbit(t)) {
    c1[t] = (c1[t] + x) % p;
    c2[t] = (c2[t] + ad1) % p;
  }
  for (int t = r + 1; t <= n; t += lowbit(t)) {
    c1[t] = (c1[t] - x) % p;
    c1[t] = (c1[t] + p) % p;
    c2[t] = (c2[t] - ad2) % p;
    c2[t] = (c2[t] + p) % p;
  }
}
inline int qwq(int i) {
  int res = 0;
  for (int t = i; t > 0; t -= lowbit(t)) {
    res = (res + (ll)i * c1[t] % p) % p;
    res = (res - c2[t]) % p;
    res = (res + p) % p;
  }
  return res;
}
inline int query(int l, int r) {
  int res = (qwq(r) - qwq(l - 1)) % p;
  return (res + p) % p;
}
/**
 * @brief 第一次 DFS
 * @param u 当前节点
 * @param f 父节点
 */
void dfs1(int u, int f) {
  fa[u] = f;                // 标记节点的父亲
  siz[u] = 1;               // 标记节点的大小
  depth[u] = depth[f] + 1;  // 标记节点的深度
  int t = -1;               // 最重子树的大小
  for (auto v : adj[u]) {
    if (v == f) continue;
    dfs1(v, u);  // 进行 DFS，求出子树大小等
    siz[u] += siz[v];
    if (siz[v] > t) {
      t = siz[v];
      son[u] = v;  // 存储重子树
    }
  }
}
/**
 * @brief 第二次 DFS
 * @param u 当前节点
 * @param topf 该链的起始节点
 */
void dfs2(int u, int topf) {
  top[u] = topf;                           //
  id[u] = ++cnt;                           // 标记节点的新编号
  if (w[u] != 0) add(id[u], id[u], w[u]);  // 节点的初始权值
  if (son[u] == 0) return;                 // 没有重儿子则返回
  dfs2(son[u], topf);      // 搜索重儿子，保证重链上 id 递增
  for (auto v : adj[u]) {  // 对于每个轻儿子
    if (v == son[u] || v == fa[u]) continue;
    dfs2(v, v);  // 从轻儿子开始一条链
  }
}
int queryPath(int u, int v) {
  int res = 0;
  while (top[u] != top[v]) {
    if (depth[top[u]] < depth[top[v]]) swap(u, v);
    res = (res + query(id[top[u]], id[u])) % p;
    u = fa[top[u]];
  }
  if (depth[u] > depth[v]) swap(u, v);
  res = (res + query(id[u], id[v])) % p;
  return res;
}
void addPath(int u, int v, int k) {
  k %= p;
  while (top[u] != top[v]) {
    if (depth[top[u]] < depth[top[v]]) swap(u, v);
    add(id[top[u]], id[u], k);
    u = fa[top[u]];
  }
  if (depth[u] > depth[v]) swap(u, v);
  add(id[u], id[v], k);
}
int querySon(int u) { return query(id[u], id[u] + siz[u] - 1); }
void addSon(int u, int k) {
  k %= p;
  add(id[u], id[u] + siz[u] - 1, k);
}

int main() {
  cin >> n >> m >> r >> p;
  for (int i = 1; i <= n; ++i) cin >> w[i];
  for (int i = 1; i < n; ++i) {
    int u, v;
    cin >> u >> v;
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  dfs1(r, 0);
  dfs2(r, r);
  while (m--) {
    int op, x, y, z;
    cin >> op >> x;
    if (op == 1) {
      cin >> y >> z;
      addPath(x, y, z);
    } else if (op == 2) {
      cin >> y;
      cout << queryPath(x, y) << endl;
    } else if (op == 3) {
      cin >> z;
      addSon(x, z);
    } else {
      cout << querySon(x) << endl;
    }
  }
}
